#include <iostream>
#include <cstdio>

// list

struct empty {};

template <long long value, typename T>
struct list
{
	static const int digit = value;
	typedef T Tail;
};

// big_int

template <int num> struct big_int
{
	typedef typename list
	<
		num % 10,
		typename big_int <num / 10> ::type
	> type;
};

template<>
struct big_int <0>
{
	typedef empty type;
};

// if_type

template <bool con, typename THEN, typename ELSE> 
struct if_type;

template <typename THEN, typename ELSE> 
struct if_type <true, THEN, ELSE>
{
   typedef THEN type;
};

template <typename THEN, typename ELSE> 
struct if_type <false, THEN, ELSE>
{
   typedef ELSE type;
};
// equal_type

template <typename A, typename B>
struct equal_type
{
	static const bool value = false;
};

template <typename A>
struct equal_type <A, A>
{
	static const bool value = true;
};

// delete_zeros

template <typename num> 
struct delete_zeros
{
	typedef typename if_type
	<
		equal_type
		<
			typename delete_zeros
			<
				typename num::Tail
			> ::type, 
			empty
		> :: value && (num::digit == 0),
		empty,
		typename list
		<
			num::digit,
			typename delete_zeros
			<
				typename num::Tail
			> ::type
		>
	> ::type type;
};

template <>
struct delete_zeros <empty>
{
	typedef empty type;
};
// add

template <typename num1, typename num2, int carry>
struct add
{
	typedef typename list
	<
		(num1::digit + num2::digit + carry) % 10,
		typename add
		<
			typename num1::Tail,
			typename num2::Tail,
			(num1::digit + num2::digit + carry) / 10
		> ::type
	> type;
};

template <typename num1, int carry> 
struct add <num1, empty, carry>
{
	typedef typename list
	<
		(num1::digit + carry) % 10,
		typename add
		<
			typename num1::Tail,
			empty,
			(num1::digit + carry) / 10
		> ::type
	> type;
};

template <typename num2, int carry> 
struct add <empty, num2, carry>
{
	typedef typename list
	<
		(num2::digit + carry) % 10,
		typename add
		<
			empty,
			typename num2::Tail,
			(num2::digit + carry) / 10
		> ::type
	> type;
};

template <int carry> 
struct add <empty, empty, carry>
{
	typedef typename big_int <carry> :: type type;
};

// Compare

template<int num1, int num2, int result> 
struct compare_int;

template<int num1, int num2> 
struct compare_int<num1, num2, 1>
{
   static const int value = 1;
};

template<int num1, int num2> 
struct compare_int <num1, num2, -1>
{
   static const int value = -1;
};

template <int num> 
struct compare_int <num, num, 0>
{
   static const int value = 0;
};

template <int num1, int num2> 
struct compare_int <num1, num2, 0>
{
   static const int value = ((num1 < num2) ? -1 : 1);
};

template <typename num1, typename num2>
struct compare
{
	static const int value = 
	compare_int
	<
		num1::digit,
		num2::digit,
		compare
		<
			num1::Tail,
			num2::Tail
		> ::value
	> ::value;
};

template <typename num1> 
struct compare <num1, empty>
{
   static const int value = 1;
};

template <typename num2> 
struct compare <empty, num2>
{
   static const int value = -1;
};

template <> 
struct compare <empty, empty>
{
   static const int value = 0;
};

// subtract

template <typename num1, typename num2, int carry>
struct subtract_stupid
{
	typedef typename list
	<
		num1::digit - (num2::digit + carry) + ((num1::digit >= (num2::digit + carry)) ? 0 : 10),
		typename subtract_stupid
		<
			typename num1::Tail,
			typename num2::Tail,
			(num1::digit >= num2::digit + carry) ? 0 : 1
		> ::type
	> type;
};

template <typename num1, int carry>
struct subtract_stupid <num1, empty, carry>
{
	typedef typename list
	<
		num1::digit - carry + ((num1::digit >= carry) ? 0 : 10),
		typename subtract_stupid
		<
			typename num1::Tail,
			empty,
			(num1::digit >= carry) ? 0 : 1
		> ::type
	> type;
};

template <int carry>
struct subtract_stupid <empty, empty, carry>
{
	typedef empty type;
};

template <typename num1, typename num2> struct get_result
{
	typedef typename delete_zeros
	<
		typename subtract_stupid
		<
			typename num1,
			typename num2,
			0
		> ::type
	> ::type type;
};

template<>
struct get_result <empty, empty>
{
	typedef empty type;
};

template <typename num1, typename num2>
struct subtract
{
	typedef typename get_result
	<
		typename if_type
		<
			(compare <num1, num2> ::value > 0),
			num1,
			empty
		> ::type,
		typename if_type
		<
			(compare <num1, num2> ::value > 0),
			num2,
			empty
		> ::type
	> ::type type;
};

template <typename num>
struct subtract <num, num>
{
	typedef empty type;
};

// Help for multyply
template <typename num, int digit_, int carry>
struct multiply_digit
{
	typedef typename list
	<
		(num::digit * digit_ + carry) % 10,
		typename multiply_digit
		<
			typename num::Tail,
			digit_,
			(num::digit * digit_ + carry) / 10
		> ::type
	> type;
};

template <typename num, int carry>
struct multiply_digit <num, 0, carry>
{
	typedef empty type;
};

template <int digit, int carry>
struct multiply_digit <empty, digit, carry>
{
	typedef typename big_int <carry> :: type type;
};

template <int carry>
struct multiply_digit <empty, 0, carry>
{
	typedef empty type;
};

template <typename num> struct multiply_ten
{
	typedef list <0, num> type;
};

template <>
struct multiply_ten <empty>
{
	typedef empty type;
};

// Multiply
template <typename num1, typename num2>
struct multiply
{
	typedef typename add
	<
		typename multiply_digit
		<
			num1,
			num2::digit,
			0
		> ::type,
		typename multiply_ten
		<
			typename multiply
			<
				num1,
				typename num2::Tail
			> ::type
		> ::type,
		0
	> :: type type;
};

template <typename num1>
struct multiply <num1, empty>
{
	typedef empty type;
};

template<typename num2> 
struct multiply <empty, num2>
{
   typedef empty type;
};

template<> 
struct multiply <empty, empty>
{
   typedef empty type;
};

// divide

template <typename num1, typename num2>
struct find_digit
{
	static const int value = (compare<num1, num2> ::value >= 0) 
		? (1 + find_digit <typename subtract <num1, num2> ::type, num2> ::value)
		: 0;
};

template <typename num2> 
struct find_digit <empty, num2>
{
	static const int value = 0;
};

template <typename num1, typename num2>
struct divide
{
	typedef typename divide 
	<
		typename num1::Tail,
		num2
	> ::type prefix;
	
	typedef typename add
	<
		typename big_int
		<
			find_digit
			<
				typename subtract
				<
					num1,
					typename multiply_ten <typename multiply <num2, prefix> ::type> ::type
				> ::type,
				num2
			> ::value
		> ::type,
		typename multiply_ten <prefix> ::type,
		0
	> ::type type;
};

template <typename num2>
struct divide <empty, num2>
{
	typedef empty type;
};

// ostream 

template <int a, typename T>
std::ostream& operator << (std::ostream& output, list <a, T> List_)
{
	return output << T() << List_.digit;
};

std::ostream& operator << (std::ostream& output, empty List_)
{
	return output;
};

typedef big_int <987654321> ::type num1;
typedef big_int <12345> ::type num2;

typedef add <num1, num2, 0> ::type sum1;
typedef multiply <num1, num2> ::type mul1;
typedef subtract <num1, num2> ::type subs1; 
typedef divide <num1, num2> ::type div1;
typedef multiply <num2, div1> ::type mul2;
typedef subtract <num1, mul2> ::type sub2;
typedef add <sub2, mul2, 0> ::type sum2;

int main()
{
	std::cout << sum1() << std::endl;
	std::cout << mul1() << std::endl;
	std::cout << subs1() << std::endl;
	std::cout << div1() << std::endl;
	std::cout << mul2() << std::endl;
	std::cout << sub2() << std::endl;
	std::cout << sum2() << std::endl;
	std::cout << num1() << std::endl;
}
